﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using ScrumTable.BL.DM.DataManagement;
using ScrumTable.Common;
using ErrorType = System.Collections.ObjectModel.ObservableCollection<ScrumTable.UI.ViewModel.IScrumItemViewModel<ScrumTable.BL.DM.DataManagement.DomainBase>>;

#endregion

namespace ScrumTable.UI.ViewModel.Tools.Toast
{

  
    /// <summary>
    /// Description of the class
    /// </summary>
    public class ErrorToastProvider : ToastBaseProvider
    {
     
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------
        
        

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        public sealed override ToastType ToastType
        {
            get { return ToastType.Error; }
        }

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------
        public ErrorToastProvider(ToastList toasts ) : base(toasts)
        {
            ScrumDataGlobal.DataContext.SyncError += OnDataContextSyncError;
            ScrumDataGlobal.DataContext.ElementChanged += OnDataContextElementChanged;
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        protected override void ReleaseManagedResources()
        {
            if (ScrumDataGlobal.DataContext != null)
            {
                ScrumDataGlobal.DataContext.SyncError -= OnDataContextSyncError;
                ScrumDataGlobal.DataContext.ElementChanged -= OnDataContextElementChanged;
            }
            base.ReleaseManagedResources();
        }


        private void RemoveOkElement(DomainChangedEventArgs child)
        {
            if (child.ContainsPropertyName("IsSynchronized") || child.ContainsPropertyName("IsDisposed"))
            {
                var errorList = Toasts.GetToastsByType(ToastType);
                for (int index = errorList.Count - 1; index >= 0; index--)
                {
                    ToastItem errorToast = errorList[index];
                    var errorChilds = errorToast.GetContent<ErrorType>();
                    var item = errorChilds.FirstOrDefault(x => x.Id == child.ChangedElement.Id);
                    if (item != null && (item.Original.IsSynchronized || ((IDisposableObject)item.Original).IsDisposed))
                    {
                        errorChilds.Remove(item);
                    }
                    if (errorChilds.Count == 0)
                    {
                        Toasts.Remove(errorToast);
                    }
                }
            }
        }


        private void CleanDisposed()
        {
            var errorToasts = Toasts.GetToastsByType(ToastType);
            if (errorToasts.Count > 0)
            {
                var errors = errorToasts.ToArray();
                foreach (var errorPair in errors)
                {
                    var errorPairItems = errorPair.GetContent<ErrorType>().ToArray();
                    foreach (var error in errorPairItems)
                    {
                        if (((IDisposableObject)error).IsDisposed)
                        {
                            errorPair.GetContent<ErrorType>().Remove(error);
                        }
                    }
                    if (errorPair.GetContent<ErrorType>().Count == 0)
                    {
                        Toasts.Remove(errorPair);
                    }
                }
            }
        }
 
        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------



        private void OnDataContextElementChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e is MultipleDomainChangedEventArgs)
            {
                foreach (var child in ((MultipleDomainChangedEventArgs)e).Children)
                {
                    RemoveOkElement(child);
                }
            }
            else
            {
                RemoveOkElement((DomainChangedEventArgs)e);
            }
            //TODO IsDisposed gets not fired if current is a workflow error and than on a other pc the same element gets moved
            //should be not here
            CleanDisposed();
        }


        private void OnDataContextSyncError(object sender, DomainSyncErrorArgs e)
        {

            if (e.ErrorInfo.Count == 0 && e.IsUnkown && (e.ErrorItem == null || e.ErrorItem.SynchronizationErrors == null || e.ErrorItem.SynchronizationErrors.Count == 0))
            {
                return;
            }

            IScrumItemViewModel<DomainBase> viewModelData = null;
            if (e.ErrorItem is Task)
            {
                viewModelData = new TaskViewModel((Task)e.ErrorItem);
            }
            else if (e.ErrorItem is UserStory)
            {
                viewModelData = new UserStoryViewModel((UserStory)e.ErrorItem);
            }
            else if (e.ErrorItem is Bug)
            {
                viewModelData = new BugViewModel((Bug)e.ErrorItem);
            }

            if (viewModelData != null)
            {
                var knownError = viewModelData.SynchronizationErrors.FirstOrDefault(x => x.FieldErrorReason != DomainSyncErrorReason.Unknown);
                if (knownError != null)
                {
                    AddErrorToList(knownError.FieldErrorReason.ToString(), viewModelData);
                    return;
                }
                var unknownError = viewModelData.SynchronizationErrors.FirstOrDefault(x => x.FieldErrorReason == DomainSyncErrorReason.Unknown);
                if (unknownError != null)
                {
                    AddErrorToList(unknownError.Error.Message, viewModelData);
                    return;
                }
                AddErrorToList("Others", viewModelData);
            }
        }

        private void AddErrorToList(string massage, IScrumItemViewModel<DomainBase> item)
        {
            var itemPair = Toasts.FirstOrDefault(toastItem => toastItem.TitleKey == massage);
            if (itemPair == null)
            {
                var list = new ObservableCollection<IScrumItemViewModel<DomainBase>>();
                itemPair = new ToastItem(massage, ToastType, list);
                Toasts.Add(itemPair);
                list.Add(item);
            }
            else
            {
                if (!itemPair.GetContent<ErrorType>().Contains(item))
                {
                    itemPair.GetContent<ErrorType>().Add(item);
                }
            }
        }
        #endregion

 
    }
}